package com.atguigu.eduservice.controller;


import com.atguigu.commonutils.R;
import com.atguigu.eduservice.entity.EduTeacher;
import com.atguigu.eduservice.entity.vo.TeacherQuery;
import com.atguigu.eduservice.service.EduTeacherService;
import com.atguigu.servicebase.exceptionhandler.GuliException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 讲师 前端控制器
 * </p>
 *
 * @author testjava
 * @since 2020-06-01
 */
//swagger可以直接整合到service_edu中，但在后面会有很多的模块使用swagger进行测试，所以就不专门写在service_edu，
//而在外面建一个公共模块，把swagger放到公共模块中，供所有模块使用
/* 因为swagger配置到了common的service_base中，并不是在service_edu中，那么想要在
 * service_edu中用common的service_base中的东西应该怎么用呢？
 * 可以在service_edu引入service_base，但为了方便直接将service_base引入到service中了
 *
 * 注意：在以上配置完成之后，按道理说SwaggerConfig配置类由@Configuration注解，springboot启动时，SwaggerConfig配置类可以加载，
 * 但因为SwaggerConfig配置类没有写在service_edu中，而是写在了common的service_base中，所以目前加载不到，所以要在EduApplication启动类上
 * 添加@ComponentScan(basePackages = {"com.atguigu"})注解，设置包扫描规则，如果不加这个注解，则默认只扫描当前项目模块中的类，从外往里扫，从EduApplication启动类开始扫，然后扫当前项目各个包下的带@Configuration的类
 * 而别的项目的SwaggerConfig配置类不能加载到
*/
/*
* 使用统一返回结果类R，需要先将将common_utils引入到service中，这样才能使用R类中的相关内容
*/
@Api(description="讲师管理")
@RestController
@RequestMapping("/eduservice/teacher") //这里需要加上斜杠
//在controller上添加@CrossOrigin注解，可以解决跨域问题
@CrossOrigin //解决跨域
public class EduTeacherController {

    //访问地址： http://localhost:8001/eduservice/teacher/findAll
    //把service注入
    @Autowired
    private EduTeacherService teacherService;

    //1 查询讲师表中的所有数据
    //查询一般用get提交，添加post，修改put，删除delete
    //rest风格
    @ApiOperation(value = "所有讲师列表")
    @GetMapping("findAll") //这里可以加斜杠，也可以不加斜杠，即可用 "findAll" ，也可以用 "/findAll"
    public R findAllTeacher() {
        //调用service的方法实现查询所有的操作
        List<EduTeacher> list = teacherService.list(null); //查询所有，即没有条件，可以传null
        return R.ok().data("items", list);
    }

//    public List<EduTeacher> findAllTeacher() {
//        //调用service的方法实现查询所有的操作
//        List<EduTeacher> list = teacherService.list(null); //查询所有，即没有条件，可以传null
//        return list;
//    }

    //2 逻辑删除讲师的方法
    //首先要在配置类中配置逻辑删除插件，然后需要在实体类EduTeacher中的对应属性上添加@TableLogic逻辑删除注解
    //访问地址： http://localhost:8001/eduservice/teacher/1
    @ApiOperation(value = "逻辑删除讲师")
    @DeleteMapping("{id}") //id只需要通过路径进行传递
    public R removeTeacher(@ApiParam(name = "id", value = "讲师ID", required = true) @PathVariable String id) { //获取到路径中的id值
        boolean flag = teacherService.removeById(id);
        if (flag) {
            return R.ok();
        } else {
            return R.error();
        }
    }

//    public boolean removeTeacher(@ApiParam(name = "id", value = "讲师ID", required = true) @PathVariable String id) { //获取到路径中的id值
//        boolean flag = teacherService.removeById(id);
//        return flag;
//    }

    //3 分页查询讲师方法
    //current 当前页
    //limit 每页记录数
    //首先要在配置类EduConfig中配置mybatisplus的分页插件
    /*
    * 最后的统一异常处理
    * 为了能够通用，在所以在common子模块的service_base子子模块中创建com.atguigu.servicebase.exceptionhandler包，
    * 在包中创建自定义的GlobalExceptionHandler类，然后再类上添加@ControllerAdvice注解，在类中写异常处理方法，
    * 在方法上添加@ExceptionHandler(Exception.class)注解，指定出现什么异常执行这个方法，注解中的Exception可以替换为
    * 特定的异常，如ArithmeticException，也可以是自定义的异常，如GuliException，
    * 如果需要返回json数据，则需要在方法上再添加一个@ResponseBody注解
    */
    @GetMapping("pageTeacher/{current}/{limit}")
    public R pageListTeacher(@PathVariable long current,
                             @PathVariable long limit) {

        //创建page对象
        //注意：这里要把current, limit传进去，否则查询的是所有，没有分页
        Page<EduTeacher> pageTeacher = new Page<>(current, limit);

        //测试异常
        //注意这里如果使用自定义异常，则就不是系统自带的异常，那么系统不会自动抛出，需要手动抛出自定义异常，需要用到try...catch...
        //如果是系统自带的异常，则可以不用手动抛出，系统会自动抛出异常，不需要用到try...catch...这里只是为了测试，所以也手动抛出了
        try {
            int i = 10/0;
        }catch (Exception e) {
            //执行自定义异常
            //手动抛出自定义异常，并调用自定义异常的有参构造方法，传入异常状态码和异常提示信息
            //需要try...catch...先捕获异常再抛出
            throw new GuliException(20001, "执行了自定义异常处理...");
        }


        //调用方法实现分页
        //调用方法时，底层封装，把分页所有数据封装到 pageTeacher 对象里面
        //在mapper中调用selectPage方法，而在service中调用page方法
        //page方法中的第一个参数是new的Page对象，第二个参数是条件，如果没有条件就传null
        teacherService.page(pageTeacher, null);

        long total = pageTeacher.getTotal(); //总记录数
        List<EduTeacher> records = pageTeacher.getRecords(); //每页数据list集合
        //因为需要返回的数据有两个
        //返回数据第一种写法
        return R.ok().data("total", total).data("rows", records);
        //返回数据第二种写法
//        Map map = new HashMap();
//        map.put("total", total);
//        map.put("rows", records);
//        return R.ok().data(map);
    }

    //4 条件查询带分页的方法
    //把查询条件值封装到对象里面，把对象传递到接口里面
    //创建一个VO实体类TeacherQuery
    @PostMapping("pageTeacherCondition/{current}/{limit}")
    public R pageTeacherCondition(@PathVariable long current, @PathVariable long limit,
                                  @RequestBody(required = false) TeacherQuery teacherQuery) {
                //这里@RequestBody可加可不加，它的作用是（前端可以）使用json传递数据，把json数据封装到对应的对象中去，如果后台这里加了
                //@RequestBody，那么前端再传数据用json传，传过来的数据就被封装到TeacherQuery中，
                //使用@RequestBody的注意事项，1 需要使用post提交方式，get取不到，2 因为是多条件，传递的值可能一个都没有，
                //所以不能单独使用@RequestBody，而要用@RequestBody(required = false)，
                //@RequestBody(required = false) TeacherQuery teacherQuery表示参数值可以为空
        //创建page对象
        Page<EduTeacher> pageTeacher = new Page<>(current, limit);

        //构建条件
        QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
        //多条件组合查询
          //mybatis学过 动态sql，这里测操作类似
          //判断条件值是否为空，如果不为空，拼接条件
        String name = teacherQuery.getName();
        Integer level = teacherQuery.getLevel();
        String begin = teacherQuery.getBegin();
        String end = teacherQuery.getEnd();
        //注意这里用的是spring的StringUtils，StringUtils.isEmpty(name)，判断为空或者为空字符串，它的效果和str1==null||str1.equals("")效果一样，
        //注意是str1==null||str1.equals("")，而不是str1.equals("")||str1==null，先判断是不是对象，如果是，再判断是不是空字符串
        //注意这里每个值都要做判断，所以要用多个if，而不能使用if...else if...
        if(!StringUtils.isEmpty(name)) {
            //构建条件
            //调用的方法中第一个参数是数据表中的字段名称，而不是实体类中的属性名称，第二个参数是传的值
            wrapper.like("name", name);
        }
        if(!StringUtils.isEmpty(level)) {
            wrapper.eq("level", level);
        }
        if(!StringUtils.isEmpty(begin)) {
            wrapper.ge("gmt_create", begin);
        }
        if(!StringUtils.isEmpty(end)) {
            wrapper.le("gmt_create", end);
        }

        //调用方法实现条件查询带分页功能
        teacherService.page(pageTeacher, wrapper);

        long total = pageTeacher.getTotal(); //总记录数
        List<EduTeacher> records = pageTeacher.getRecords(); //数据list集合
        return R.ok().data("total", total).data("rows", records);
    }

    //5 添加讲师接口的方法
    //在实体类EduTeacher的gmtCreate和gmtModified属性上分别添加@TableField(fill = FieldFill.INSERT)
    // 和@TableField(fill = FieldFill.INSERT_UPDATE)注解，实现自动填充
    //因为自动填充在后面的所有模块中都用到，所以在common子模块的service_base子子模块中创建com.atguigu.servicebase.handler包，
    //在包中创建MyMetaObjectHandler类，并实现MetaObjectHandler接口
    //在启动类上添加@ComponentScan(basePackages = {"com.atguigu"})注解，它能扫描MyMetaObjectHandler类上的注解@Component，
    //把它交给spring管理
    //注意用swagger测试时不需要传gmtCreate和gmtModified，这两个值是自动填充的，id值也不需要，这个值是自动生成出来的
    @PostMapping("addTeacher")
    public R addTeacher(@RequestBody EduTeacher eduTeacher) {
        //这里使用的是@RequestBody EduTeacher eduTeacher，而不是@RequestBody(required = false) EduTeacher eduTeacher，
        //因为这个值eduTeacher必须要有
        boolean save = teacherService.save(eduTeacher);
        if (save) {
            return R.ok();
        } else {
            return R.error();
        }
    }

    //讲师修改功能，1 首先根据讲师id进行查询，2 然后再进行讲师修改功能
    //根据讲师id进行查询
    @GetMapping("getTeacher/{id}")
    public R getTeacher(@PathVariable String id) {
        EduTeacher eduTeacher = teacherService.getById(id);
        return R.ok().data("teacher", eduTeacher);
    }

    //讲师修改功能
    //修改按道理说应该用put提交，而这里我们传值用的是对象和@RequestBody，所以这里改成了post提交，
    //如果不用@RequestBody，则这里用put提交也可以
    //这里如果想用put提交，并且使用@RequestBody，可以参考课件，id值需要手动设置进去
    //这里传的值eduTeacher包含id值
    //注意用swagger测试的时候，需要有id值，因为要根据id值进行修改，而不能有gmtCreate和gmtModified，这两个值是自动填充的
    @PostMapping("updateTeacher")
    public R updateTeacher(@RequestBody EduTeacher eduTeacher) {
        boolean flag = teacherService.updateById(eduTeacher);
        if (flag) {
            return R.ok();
        } else {
            return R.error();
        }
    }

}

